home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994…tember: Reference Library / Dev.CD Sep 94.toast / Periodicals / develop / develop Issue 11 / develop 11 code / The NetWork Project / Examples (Sources) / RemoteJob.p < prev    next >
Encoding:
Text File  |  1992-07-15  |  16.6 KB  |  610 lines  |  [TEXT/MPS ]

  1. {
  2.     File:        RemoteJob.p
  3.  
  4.     Contains:    remote launching example
  5.  
  6.     Written by:    G. Sawitzki, StatLab Heidelberg
  7.  
  8.     Copyright:    © 1989-1991 The NetWork Project, StatLab Heidelberg.
  9.                 © Copyright 1989-1991 Günther Sawitzki, Heidelberg. All rights reserved.
  10.     Change History (most recent first):
  11.  
  12.         <9+>      8/2/91    gs        remove NLExit, ExitNetWork
  13.  
  14.     To Do:
  15. }
  16.  
  17.  
  18. program RemoteJob; {0.1d5}
  19.  
  20. uses     
  21.     Errors,
  22.     Types, QuickDraw, Menus,
  23.     Memory,
  24.     Fonts,Windows,TextEdit,Dialogs,
  25.     OsUtils,Files,
  26.     Events,Desk,
  27.     NetWork, NetWorkLookup,Traps,
  28.     ObjIntf,SchedulerUnit,PasLibIntf;
  29.  
  30. {-----------------------------------------------------------------------}
  31. {remote launching example. This can be used to do a remote launch of 
  32. pre-NetWork programs. A simple use would be to have a remote MPW
  33. cooperating on a build.
  34.  
  35. The sending part looks for a file named remote.job in the system folder.
  36. If the file exists, its data fork is transferred according to the user 
  37. selected settings.
  38.  
  39. Upon receipt of a message, the receiving part stores the file as file 
  40. UserStartUp•Remote.Job in the system folder, and tries to launch the 
  41. proper target, eg. MPW.
  42.  
  43. To use it, place a copy of MPW and a suitable startup file in the
  44. NetWork folder on the receiving machine.
  45.  
  46. • under construction • Alpha release notes:
  47.  
  48. spare does a lot of debugging. should be used only with source in hand.
  49.  
  50. To do:
  51. Which of the ping games should be allowed ?
  52. Provide prototype for collision detection,improper format handling.
  53. File error handling.
  54. System 7 support for reduced MPW shell (to be introduced with ETO 3).
  55.  
  56. Done:
  57.  
  58. 0.1d4    ##
  59. 0.1d3    adapted to event-based scheduler
  60. 0.1d2    default received file type to TEXT
  61. }
  62.  
  63. {=============================================================================}
  64. {    our message header format    }
  65.  
  66. const cFormatVersion='VS 1';    {good habit: keep a version stamp around while
  67.                                 you are experimenting}
  68.  
  69. type 
  70.     tHeaderPtr=^tHeader;
  71.     tHeader=record
  72.         idStamp:longint;
  73.         signature:longint;    {whom shall we activate ?}
  74.         whereMode:integer;    {code for determining the target system.
  75.                             see MsgEvaluation}
  76.     end;
  77.  
  78. var sendHeader    :tHeader;        {we keep one copy around to define defaults}
  79.  
  80. {=============================================================================}
  81. {    our message handlers. We will work with static message handler, so we
  82. instantiate one of each and keep it around all the time}
  83.  
  84. {-----------------------------------------------------------------------------}
  85. {    sending part: generate a task if a command is given or a commenand file
  86.     is around    }
  87.  
  88. type
  89.     tRemoteGenerator= Object(tTaskGenerator)
  90.         function tRemoteGenerator.newTask(var msg:MsgPtr):boolean; override;
  91.     end;
  92.  
  93. var RemoteGenerator    : tRemoteGenerator;
  94.  
  95. {-----------------------------------------------------------------------------}
  96. {    recipients part: a message is considered usable if the header has the
  97.     correct format id. MsgEvaluation stores the information to a file, and
  98.     sends an (empty) message to launch the recipient.}
  99.  
  100. type 
  101.     tRemoteHandler = Object(tTaskhandler)
  102.         FormatVersion:longint;                        {we can only use messages of this version}
  103.         procedure tRemoteHandler.init; override;    {sets FormatVersion to cFormatVersion} 
  104.         function tRemoteHandler.MsgUsable(var msg:msgPtr):boolean; override;
  105.         procedure tRemoteHandler.MsgEvaluation(var msg:msgPtr); override;
  106.     end;
  107.     
  108. var RemoteHandler : tRemoteHandler;
  109.  
  110.  
  111. {=============================================================================}
  112. {    global constants and variables    }
  113.  
  114. const    
  115.     cMaxJobFileSize        = 8*1024;    {to improve: work with any file sizes}
  116.  
  117.     {default file names}
  118.     cJobFileToSend        ='Remote.Job';
  119.     cJobFileReceived    ='UserStartUp•Remote.Job';
  120. var 
  121.     JobFileToSend,
  122.     JobFileReceived        : str255;
  123.  
  124.     done, front            : boolean; 
  125.     mode                : integer;
  126.     gSleep                : longint;
  127.     
  128.     gTextValid            : boolean;
  129.     gTextToSend         : Str255;
  130.         {if gTextValid is true, gTextToSend holds a text to be transmitted}
  131.  
  132.  
  133.     {=============================================================================}
  134.     {    Application layer    }
  135.  
  136.     {-----------------------------------------------------------------------------}
  137.     {    File access routines    }
  138.  
  139.  
  140.  
  141. function CheckStatus(whichFile:str255):osErr;
  142.  
  143.         {Return NoErr if a file named whichFile exists and is ready for sending.
  144.         This is used to check for the existence of cJobFileToSend. 
  145.         To do: it should guarantee that the file is not open for write
  146.         in order to guarantee that writing of the job file is finished. }
  147.         
  148. var myfinfo:Finfo;
  149. begin
  150.     CheckStatus:=GetFInfo(whichFile,0,myfinfo);
  151. end;
  152.  
  153.  
  154. procedure ReadJobFile(whichFile:str255;var filesize:longint;var where:ptr);
  155.  
  156.         {Open a file and read the contents to the buffer indicated by
  157.         where. Return the number of bytes read. Delete the file.}
  158.         
  159. VAR
  160.     InputFile: FILE;
  161.     myerr:osErr;
  162. begin
  163.     if spare then debugstr(concat('Start ReadJobFile ',whichfile,' Type g to continue.'));
  164.     filesize:=0; 
  165.     reset(InputFile, whichfile); 
  166.     if (ioresult=0) & (where<>nil) then 
  167.     begin
  168.         filesize:= byteread(InputFile, where^, GetPtrSize(where));
  169.         myErr:=ioResult;
  170.         if spare & (myerr<>noErr) then debugstr('error on read');
  171.         close(inputfile);
  172.         PLPurge(JobFileToSend);
  173.     END;
  174. end;
  175.  
  176.  
  177. procedure WriteJobFile(whichFile:str255;filesize:longint; where:ptr);
  178.  
  179.     {Create a file and write the contents to the buffer indicated by
  180.     where. Set type and crator as for an MPW text file. close the file.}
  181.  
  182. const cDefaultVolRef=0;
  183. VAR
  184.     OutputFile: FILE;
  185.     myErr:Oserr;
  186.     fndrinfo:Finfo;
  187. begin
  188.     if spare then debugstr(concat('Start WriteJobFile: ',whichfile,' Type g to continue.'));
  189.     rewrite(OutputFile, whichfile); 
  190.     if ioresult=0 then {to improve:handle multiple files}
  191.     begin
  192.         filesize:=bytewrite(OutputFile, where^, filesize);
  193.         close(OutputFile);
  194.         if getfinfo(JobFileReceived, cDefaultVolRef, fndrinfo)=NoErr then
  195.         begin
  196.             fndrinfo.fdtype := 'TEXT';    {clame it is from MPW, as default}
  197.             fndrinfo.fdCreator := 'MPS ';
  198.             if  Setfinfo(JobFileReceived, cDefaultVolRef, fndrinfo) <> noErr then;
  199.         END;
  200.  
  201.     END;
  202. end;
  203.  
  204.  
  205. {=============================================================================}
  206. {    NetWork specific part of layer    }
  207.  
  208.  
  209. {-----------------------------------------------------------------------------}
  210. const    {several modes to identify the machine on which a process shall be launched.
  211.     -- to experiment with }
  212.  
  213.     LocalMode    =1;    {launch on local machine}
  214.     RandomMode    =2;    {launch on a random machine}
  215.     NextMode    =3;    {launch on the next machine}
  216.     BroadcastMode=4;{launch on all machines}
  217.  
  218.  
  219. function newAddr(var addr:longint;mode:integer):boolean;
  220. begin    newAddr:=true;{default}
  221.     case Mode of
  222.         1 : addr := 0; { local }
  223.         2 : begin addr := NlRandom; if addr=0 then newAddr:=false;end;
  224.         3 : begin
  225.             if addr<0 then addr:=NLRandom else
  226.             addr := NlNext (addr);
  227.             if addr=0 then newAddr:=false;
  228.         end; 
  229.         4 : addr := -1; { broadcast }
  230.     end;
  231. end;
  232.  
  233.  
  234. {=============================================================================}
  235. {    message handler implementation    }
  236.  
  237. {-----------------------------------------------------------------------------}
  238. {    recipients part    }
  239.  
  240. var     MessageToPass    :msgRec;    {allocate static space to avoid heap fragmentation}
  241.  
  242.  
  243. procedure tRemoteHandler.init; override;    {sets FormatVersion to cFormatVersion} 
  244. begin
  245.     inherited init;
  246.     FormatVersion:=longint(cFormatVersion);
  247. end;
  248.  
  249. function tRemoteHandler.MsgUsable(var msg:msgPtr):boolean; override;
  250. var oksofar:boolean;
  251. begin
  252.     if spare then debugstr('RemotJob MsgUsable. Type g to continue.');
  253.     with  tHeaderPtr(msg^.MsgPrioPtr)^ do
  254.     oksofar:=(idStamp=FormatVersion);    {have we got the correct version?}
  255.     if oksofar then with msg^ do  
  256.          MsgCorePtr:=NewCorePtr(MsgCoreSize);        {to do: check size}
  257.     stamp(msg);
  258.     MsgUsable:=oksofar;
  259. end;
  260.  
  261.  
  262. procedure tRemoteHandler.MsgEvaluation(var msg:msgPtr);override;
  263. var NewMsg : MsgPtr; 
  264. begin
  265.     if spare then debugstr('RemotJob MsgEvaluation. Type g to continue.');
  266.  
  267.     {store the information as a file}
  268.     with msg^do
  269.     if (MsgCoreSize>0) & (MsgCorePtr<>nil) then writeJobFile(JobFileReceived,MsgCoreSize,MsgCorePtr);
  270.  
  271.     {now find the adressee}
  272.  
  273.     with tHeaderPtr(msg^.MsgPrioPtr)^,MessageToPass do
  274.     begin
  275.         {determine whom we should we call, using the header information}
  276.         MsgDest.p := signature;
  277.         if NewAddr(MsgDest.a, whereMode ) then begin
  278.  
  279.             MsgReply:=MsgSource; {we are just the mail. all results & complaints to sender please}
  280.  
  281.             NewMsg:=@MessageToPass;
  282.             {all other fields 0 -- does not work when compiled with -u option}
  283.             NetWorkScheduler.SendMessage(NewMsg);     {launch it}
  284.         end else if spare then debugstr('no partner.  Type g to continue.');
  285.         {leave all error handling to the scheduler}
  286.     end;
  287.     {Scheduler.HandleError(pUndefined,DisposMsg(msg));}
  288. end;
  289.  
  290.  
  291. {-----------------------------------------------------------------------------}
  292. {    sending part: we generate a task    }
  293.  
  294.  
  295. function tRemoteGenerator.newTask(var msg:MsgPtr):boolean; override;
  296. var 
  297.     oktosend:boolean;
  298. begin
  299.     if spare then debugstr('tRemoteGenerator.newTask start;g');
  300.  
  301.     if not(gTextValid) & (CheckStatus(JobFileToSend)<>noErr) then okToSend:=false
  302.     else begin
  303.         with msg^ do
  304.         begin
  305.             okToSend:= NewAddr(MsgDest.a,mode);
  306.             if okToSend then begin 
  307.                 if gTextValid then begin {messages on the fly are sent first}
  308.                     MsgCoreSize    :=length(gTextToSend);
  309.                     MsgCorePtr    :=NewCorePtr(MsgCoreSize);
  310.                     BlockMove(@gTextToSend[1],MsgCorePtr,MsgCoreSize);
  311.                     gTextValid    :=false;
  312.                 end else begin {no message on the fly, hence it must be a file}
  313.                     MsgCoreSize    :=cMaxJobFileSize;        {to improve: take real file size}
  314.                     MsgCorePtr    :=NewCorePtr(MsgCoreSize);
  315.                     ReadJobFile(JobFileToSend,MsgCoreSize,MsgCorePtr);
  316.                 end;
  317.                 if MsgCorePtr=nil then okToSend:=false
  318.                 else begin
  319.                     MsgPrioSize    :=sizeof(SendHeader);
  320.                     MsgPrioPtr    :=NewPrioPtr(MsgPrioSize);
  321.                     if MsgPrioPtr=nil then okToSend:=false {overrun or out of memory}
  322.                     else
  323.                     tHeaderPtr(MsgPrioPtr)^:=SendHeader;
  324.                 end;
  325.             end;
  326.         end;
  327.         if okToSend then begin 
  328.             Stamp(msg);
  329.             NewTask:=true;        
  330.             if spare then debugstr('tRemoteGenerator.newTask ok;g');
  331.         end else NewTask:=false;
  332.     end;
  333. end;
  334.  
  335.     {=============================================================================}
  336.     {    general routines    }
  337.  
  338.  
  339. PROCEDURE InitToolBox;    
  340. VAR
  341.     i : integer;
  342.     p : GrafPtr;
  343.     m : MenuHandle;
  344.  
  345. BEGIN
  346.     MaxApplZone;
  347.     FOR i := 1 TO 10 DO
  348.     MoreMasters;
  349.     InitGraf(@thePort);                {initialize QuickDraw}
  350.     InitFonts;                           {initialize Font Manager}
  351.     InitWindows;                       {initialize Window Manager}
  352.     InitMenus;                           {initialize Menu Manager}
  353.     TEInit;                            {initialize TextEdit}
  354.     InitDialogs(NIL);                   {initialize Dialog Manager}
  355.     InitCursor;                        {call QuickDraw to make cursor (pointer) an arrow}
  356.  
  357.     m := GetMenu (256);
  358.     AddResMenu (m, 'DRVR');
  359.     InsertMenu (m, 0);
  360.     m := GetMenu (257); InsertMenu (m, 0);
  361.     m := GetMenu (258); InsertMenu (m, 0);
  362.     DrawMenuBar;
  363.  
  364. END;
  365.  
  366.  
  367. {    Handle the about alert. Stolen from and © by J. Lindenberg, Karlsruhe 1989    }
  368.  
  369. {and here again we do the job the toolbox programmers should have done…}
  370.  
  371. function ModalFilter (dialog : DialogPtr; var ev : EventRecord; 
  372. var itemHit : integer) : boolean;
  373. begin
  374.     ModalFilter := false;
  375.     if ev.what = keydown then 
  376.     case BAnd (ev.message, 255) of
  377.         ord ('Q'): if (BAnd (ev.modifiers, cmdKey) <> 0) then begin
  378.             itemhit := cancel; ModalFilter := true;
  379.         end;
  380.         ord ('.'): begin itemhit := cancel; ModalFilter := true; end;
  381.         13 : begin itemhit := OK; modalfilter := true; end;
  382.     end;
  383. end;
  384.  
  385.  
  386. procedure About;
  387. begin
  388.     if Alert (256, @ModalFilter) = Ok then;
  389. end;
  390.  
  391.  
  392. {=============================================================================}
  393. {    set signature and names of task files    }
  394.  
  395. procedure SetNames;
  396. const     cSignature=3;
  397.     cJobFileToSend=6;
  398.     cJobFileReceived=8;
  399. var d : DialogPtr; n : integer; s : Str255; 
  400.  
  401. procedure SetMyDialog(item:integer;info:str255);
  402. var t : integer;h : Handle; box : Rect;
  403. begin
  404.     GetDItem (d, item, t, h, box);
  405.     SetIText (h, info); 
  406. end;
  407.  
  408. function GetMyDialog(item:integer):str255;
  409. var t : integer;h : Handle; box : Rect;
  410. begin
  411.     GetDItem (d, item, t, h, box);
  412.     GetIText (h, GetMyDialog); 
  413. end;
  414.  
  415. begin
  416.     d := GetNewDialog (258, nil, WindowPtr (-1));
  417.  
  418.     SetMyDialog(cJobFileToSend,JobFileToSend);
  419.     SetMyDialog(cJobFileReceived,JobFileReceived);
  420.  
  421.     s := '????'; BlockMove (@SendHeader.signature, @s[1], 4);
  422.     SetMyDialog(cSignature,s);
  423.     SelIText (d, cSignature, 0, 32767);
  424.  
  425.     repeat
  426.         ModalDialog (nil, n);
  427.         s:=GetMyDialog (cSignature);
  428.     until (n = cancel) | ((n=ok) & (length (s) = 4));
  429.  
  430.     if n = Ok then begin
  431.         {if it is ok, s contains the recent signature}
  432.         BlockMove (@s[1], @SendHeader.signature, 4);
  433.         JobFileToSend:=GetMyDialog (cJobFileToSend);
  434.         JobFileReceived:=GetMyDialog (cJobFileReceived );
  435.     end;
  436.     DisposDialog (d);
  437. end;
  438.  
  439.  
  440. procedure SendOnTheFly;
  441.     {get a command by dialog, create a message and send it.
  442.     This is an example of forcing a new task generation.}
  443.  
  444. var d : DialogPtr; n, t : integer;  h : Handle; box : Rect;
  445.     tempAddr:MsgAddr;
  446. begin
  447.     d := GetNewDialog (259, nil, WindowPtr (-1));
  448.  
  449.     repeat
  450.         ModalDialog (nil, n);
  451.     until (n = ok) | (n=cancel);
  452.     if n = Ok then begin
  453.  
  454.         GetDItem (d, 3, t, h, box);
  455.         GetIText (h, gTextToSend);     {get the text to our buffer}
  456.         gTextValid :=true;            {yes, the information is valid}
  457.         
  458.         tempAddr    := NetWorkScheduler.PrevDest;
  459.         NetWorkScheduler.DoNewTask(tempAddr,NetWorkScheduler.MyTransport);
  460.                                     {get the scheduler to fill all defaults, and call
  461.                                     newTask}
  462.     end;
  463.     DisposDialog (d);
  464. end;
  465.  
  466.  
  467. {=============================================================================}
  468. {    menu handling    }
  469.  
  470. procedure DoMenu (menu : Point);
  471. var  s : Str255;
  472. begin
  473.     case menu.v of
  474.         256 : { apple menu }
  475.         if menu.h = 1 then About
  476.         else begin
  477.             GetItem (GetMHandle (256), menu.h, s);
  478.             CheckError ('OpenDeskAcc', OpenDeskAcc (s));
  479.         end;
  480.         257 : {file and commands}
  481.         case menu.h of
  482.             1 : SetNames;
  483.             3 : SendOnTheFly;
  484.             4 : done := true;
  485.         end;
  486.         258 : {sendmode}
  487.         begin
  488.             CheckItem (GetMHandle (258), mode, false);    {uncheck old}
  489.             mode := menu.h;
  490.             CheckItem (GetMHandle (258), mode, true);     {check new}
  491.         end;
  492.     end;
  493.     HiliteMenu (0);
  494. end;
  495.  
  496.  
  497.  
  498.  
  499. {=============================================================================}
  500. {    main event    }
  501.  
  502. procedure HandleEvents;
  503. var w : windowPtr;
  504.     ev : EventRecord; 
  505. begin
  506.     if WaitNextEvent (EveryEvent, ev, gSleep, nil) then
  507.     case ev.what of
  508.         mouseDown : case FindWindow (ev.where, w) of
  509.             inMenuBar :     DoMenu (Point (MenuSelect (ev.where)));
  510.             inSysWindow :    SystemClick (ev,w);
  511.         end;
  512.         keyDown : if BAnd (ev.modifiers, cmdKey) <> 0 then
  513.         DoMenu (Point (MenuKey (chr (BAnd (ev.message, 255)))));
  514.         {*******************}
  515.         NetWorkEvt: NetWorkScheduler.HandleMsg(MsgPtr(ev.message));
  516.         {*******************}
  517.         otherwise  begin
  518.         end;{otherwise}
  519.     end {case}
  520.     else begin
  521.         NetWorkScheduler.PeriodicTask;
  522.         If NlTask<>NoErr then ProgramBreak('Error in NlTask');
  523.     end;
  524. end;
  525.  
  526.  
  527. procedure initdefaults;
  528. begin
  529.     if spare then debugstr('RemoteJob initdefaults. Type g to continue.');
  530.     done    := false; 
  531.     mode    :=NextMode;
  532.  
  533.     JobFileToSend    :=cJobFileToSend;
  534.     JobFileReceived    :=cJobFileReceived;
  535.     gTextValid    :=false;
  536.     gTextToSend    :='';
  537.     with sendHeader do
  538.     begin
  539.         idStamp:=longint(cFormatVersion);    {this is version 1 format}
  540.         signature:=longint('MPS ');    {whom shall we activate ? default: MPW}
  541.         whereMode:=LocalMode;        {the recipient should launch it locally}
  542.     end;
  543. end;
  544.  
  545.  
  546. {run HandleEvents a small number of times to get the screen etc set up}
  547. procedure initialwakeup;
  548. var count:integer;
  549. begin
  550.     gSleep := 0;
  551.     for count:=1 to 6 do begin
  552.         NetWorkScheduler.Receiving:=true;
  553.         HandleEvents;
  554.     end;
  555. end;
  556.  
  557. {find requested sleep value. Polling all clients is a bad strategy here -
  558. in general, you will not know at programming time who might be active.
  559. However Apple recommends this poor strategy. So we follow it for this example}
  560.  
  561. procedure getSleep;
  562. var tempsleep:longint;
  563. begin
  564.     gSleep:=10;{my default maximum sleep value}
  565.     tempSleep:=NetWorkScheduler.GetSleep;
  566.     if tempSleep<gSleep then gSleep:=tempSleep;
  567.     tempSleep:=NLGetSleep;
  568.     if tempSleep<gSleep then gSleep:=tempSleep;
  569.     if gSleep<0 then gSleep:=0;
  570. end;
  571.  
  572. {=============================================================================}
  573. {        }
  574.  
  575. begin
  576.     InitToolBox; 
  577.     InitDefaults;
  578.     
  579.     if InitNetwork(NetWorkEvt)<>NoErr then halt;
  580.     if NlInit<>noErr then halt;
  581.  
  582.     New(NetWorkScheduler);            {Create and Install the scheduler}
  583.     NetWorkScheduler.Init;
  584.  
  585.     new(remoteHandler);     {create a remoteHandler and introduce it to the scheduler}
  586.     NetWorkScheduler.InitTaskHandler(remoteHandler);
  587.  
  588.     if master then begin    {create a remoteGenerator and introduce it to the scheduler}
  589.         new(remoteGenerator);
  590.         NetWorkScheduler.InitTaskGenerator(remoteGenerator);
  591.     end;
  592.  
  593.     initialwakeup;        {run HandleEvents a small number of times to get the screen etc set up}
  594.     gSleep:=60;
  595.  
  596.     repeat 
  597.         NetWorkScheduler.Receiving:=true;
  598.         getSleep;
  599.         HandleEvents;
  600.         if (not master) & (NetWorkScheduler.taskhandler.NrPendingMessages=0) 
  601.         then done:=true;
  602.         NetWorkScheduler.Sending:=NetWorkScheduler.taskgenerator<>nil;    {even if there was nothing now…}
  603.     until done;
  604.  
  605.     NetWorkScheduler.Free;
  606.     {if NLExit<>noErr then halt;
  607.     if ExitNetWork <> NoErr then halt;}
  608.     
  609. end.
  610.